home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Users Group Library 1996 July
/
C-C++ Users Group Library July 1996.iso
/
vol_300
/
363_01
/
eval.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-09-23
|
15KB
|
498 lines
/***********************************************************************
*
* EVAL.C
* Expression Evaluator for 68020 Assembler
*
* Function: eval()
* Evaluates a constant expression. The p argument points to the string
* to be evaluated, and the function returns a pointer to the first
* character beyond the end of the expression. The value of the
* expression and an error code are returned via output arguments. The
* function handles errors according to the following table:
*
* Pass1 Pass1 Pass2 Pass2
* Condition Error *refPtr Error *refPtr
* ---------------- ---------- ----- ----------- -----
* Undefined symbol INCOMPLETE FALSE UNDEFINED FALSE
* Division by zero INCOMPLETE FALSE DIV_BY_ZERO FALSE
* Syntax error SYNTAX -- SYNTAX --
* Constant error x_TOO_BIG T/F x_TOO_BIG T/F
* No error OK T/F OK T/F
*
* The char pointed to by refPtr is set to TRUE if all the symbols
* encountered in the expression are backwards references or FALSE if
* at least one symbol is a forward reference.
*
* Usage: char *eval(char *p, long *valuePtr, char *refPtr, int *errorPtr)
*
* Errors: ASCII_TOO_BIG
* DIV_BY_ZERO
* INCOMPLETE
* NUMBER_TOO_BIG
* REG_LIST_SPEC
* SYNTAX
* UNDEFINED
*
* Author: Paul McKee
* ECE492 North Carolina State University, 9/24/86
*
* Modified A.E. Romer. Version 1.0
* 16 March 1991 - converted to ANSI, braces layout.
* 21 March 1991 - '.' disallowed in symbols except as first char.
* (to allow .w and .l suffixes in absolute
* addressing), '_' allowed as first character.
* 22 May 1991 - any character that is not valid in an expression
* is now the terminator.
* Sept. 1991 - '$' disallowed in symbols.
************************************************************************/
#include <stdio.h>
#include <ctype.h>
#include "asm.h"
extern char pass2;
/* Largest number that can be represented in an unsigned int
- MACHINE DEPENDENT */
#define INTLIMIT 0xFFFF
#define LONGLIMIT 0xFFFFFFFF
#define STACKMAX 5
char *evalNumber(char *p, long *numberPtr, char *refPtr, int *errorPtr)
{
int status;
long base;
long x;
char name[SIGCHARS+1];
symbolDef *symbol;
int i;
char endFlag;
*refPtr = TRUE;
if (*p == '-')
{
/* Evaluate unary minus operator recursively */
p = evalNumber(++p, &x, refPtr, errorPtr);
*numberPtr = -x;
return p;
}
else if (*p == '~')
{
/* Evaluate one's complement operator recursively */
p = evalNumber(++p, &x, refPtr, errorPtr);
*numberPtr = ~x;
return p;
}
else if (*p == '(')
{
/* Evaluate parenthesized expressions recursively */
p = eval(++p, &x, refPtr, errorPtr);
if (*errorPtr > SEVERE)
return NULL;
else if (*p != ')')
{
NEWERROR(*errorPtr, SYNTAX);
return NULL;
}
else
{
*numberPtr = x;
return ++p;
}
}
else if (*p == '$' && isxdigit(*(p+1)))
{
/* Convert hex digits until another character is
found. (At least one hex digit is present.) */
x = 0;
while (isxdigit(*++p))
{
if ((unsigned long)x > (unsigned long)LONGLIMIT/16)
NEWERROR(*errorPtr, NUMBER_TOO_BIG);
if (*p > '9')
x = 16 * x + (*p - 'A' + 10);
else
x = 16 * x + (*p - '0');
}
*numberPtr = x;
return p;
}
else if (*p == '%' || *p == '@' || isdigit(*p))
{
/* Convert digits in the appropriate base (binary,
octal, or decimal) until an invalid digit is found. */
if (*p == '%')
{
base = 2;
p++;
}
else if (*p == '@')
{
base = 8;
p++;
}
else base = 10;
/* Check that at least one digit is present */
if (*p < '0' || *p >= '0' + base)
{
NEWERROR(*errorPtr, SYNTAX);
return NULL;
}
x = 0;
/* Convert the digits into an integer */
while (*p >= '0' && *p < '0' + base)
{
if (x > (LONGLIMIT - (*p - '0')) / base)
{
NEWERROR(*errorPtr, NUMBER_TOO_BIG);
}
x = (long) ( (long) ((long) base * x) + (long) (*p - '0') );
p++;
}
*numberPtr = x;
return p;
}
else if (*p == CHAR_DELIMITER)
{
endFlag = FALSE;
i = 0;
x = 0;
p++;
while (!endFlag)
{
if (*p == CHAR_DELIMITER)
if (*(p+1) == CHAR_DELIMITER)
{
x = (x << 8) + *p;
i++;
p++;
}
else
endFlag = TRUE;
else
{
x = (x << 8) + *p;
i++;
}
p++;
}
if (i == 0)
{
NEWERROR(*errorPtr, SYNTAX);
return NULL;
}
else if (i == 3)
x = x << 8;
else if (i > 4)
NEWERROR(*errorPtr, ASCII_TOO_BIG);
*numberPtr = x;
return p;
}
else if (isalpha(*p) || *p == '.' || *p == '_')
{
/* Determine the value of a symbol */
i = 0;
/* Collect characters of the symbol's name
(only SIGCHARS characters are significant) */
do
{
if (i < SIGCHARS)
name[i++] = *p;
p++;
} while (isalnum(*p) || *p == '_' || *p == '$');
name[i] = '\0';
/* Look up the name in the symbol table, resulting
in a pointer to the symbol table entry */
status = OK;
symbol = lookup(name, &status);
/* printf("EvalNumber: Status from lookup = %04X\n", status); */
if (status == OK)
/* If symbol was found, and it's not a register
list symbol, then return its value */
if (!(symbol->flags & REG_LIST_SYM))
{
*numberPtr = symbol->value;
/* printf("The value of the symbol \"%s\" is %08lX\n",
name, *numberPtr); */
if (pass2)
*refPtr = (symbol->flags & BACKREF);
}
else
{
/* If it is a register list symbol, return error */
*numberPtr = 0;
NEWERROR(*errorPtr, REG_LIST_SPEC);
}
else
{
/* Otherwise return an error */
if (pass2)
{
NEWERROR(*errorPtr, UNDEFINED);
}
else
NEWERROR(*errorPtr, INCOMPLETE);
*refPtr = FALSE;
}
/* printf("The symbol \"%s\" is%s a backwards reference\n",
name, (*refPtr) ? "" : " not"); */
return p;
}
else
{
/* Otherwise, the character was not a valid operand */
NEWERROR(*errorPtr, SYNTAX);
return NULL;
}
return NORMAL;
}
int precedence(char op)
{
/* Compute the precedence o